package com.example.springboot_sdse_air.service;

import com.example.springboot_sdse_air.entity.MinerUExtractResultResponse;
import com.example.springboot_sdse_air.entity.MinerUGetUrlsResponse;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 功能：
 * 作者：王彬 202200111149
 * 日期：2025-04-28 10:38
 */
@Service
public class MinerULocalBatchService {
    private static final String BATCH_TASK_URL = "https://mineru.net/api/v4/file-urls/batch";
    private static final String EXTRACT_RESULT_URL = "https://mineru.net/api/v4/extract-results/batch/%s";
    private static final String AUTHORIZATION_TOKEN = "eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFM1MTIifQ.eyJqdGkiOiIxMDIwOTY4MCIsInJvbCI6IlJPTEVfUkVHSVNURVIiLCJpc3MiOiJPcGVuWExhYiIsImlhdCI6MTc0OTcwNTk2MiwiY2xpZW50SWQiOiJsa3pkeDU3bnZ5MjJqa3BxOXgydyIsInBob25lIjoiMTUzODg0NjkzNjgiLCJvcGVuSWQiOm51bGwsInV1aWQiOiI2NzE4MzFmNy02OGY5LTQ0MDctOGQzNS1mOWVjNjIwNmY1ZWUiLCJlbWFpbCI6IiIsImV4cCI6MTc1MDkxNTU2Mn0.YR-VrjuDVlGMd5i2yugJDKF2_mBXMma29A5I9yzEKWH2yqF-tPODFpo8NoembOSYsRViyyXiZTi0BdEIhe2D6w";
    private static int NUM_OF_FILES;
    private static final int MAX_RETRIES = 50; // 最大重试次数
    private static final int RETRY_DELAY_MS = 4000; // 每次重试的延迟时间，单位：毫秒

    private final RestTemplate restTemplate;

    public MinerULocalBatchService() {
        this.restTemplate = new RestTemplate();
    }

    public String getUrlsAndUploadFileBatch(List<Map<String, Object>> uploadFiles) {
//        List<String> filePaths, List<String> fileNames
        NUM_OF_FILES = uploadFiles.size();
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(AUTHORIZATION_TOKEN);

        // 设置请求体
        Map<String, Object> body = new HashMap<>();
        body.put("enable_formula", true);
        body.put("enable_table", false);
        body.put("layout_model", "doclayout_yolo");
        body.put("language", "auto");

        List<Map<String, Object>> files = new ArrayList<>();
        for (Map<String, Object> uploadFile : uploadFiles) {
            Map<String, Object> file = new HashMap<>();
            file.put("name", uploadFile.get("fileName"));
            file.put("is_ocr", false);
            files.add(file);
        }
        body.put("files", files);

        // 向MinerU发送http请求
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        try {
            ResponseEntity<MinerUGetUrlsResponse> response = restTemplate.postForEntity(
                    BATCH_TASK_URL, requestEntity, MinerUGetUrlsResponse.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null
                    && response.getBody().getCode() == 0 && response.getBody().getMsg().equals("ok")) {
                String batchId = response.getBody().getData().getBatchId();
                List<String> urls = response.getBody().getData().getFileUrls();

                // 开始上传文件!!!
                for (int i = 0; i < urls.size(); i++) {
                    String filePath = (String) uploadFiles.get(i).get("filePath");
                    String fileUrl = urls.get(i);
                    System.out.println(filePath);
                    System.out.println(fileUrl);
                    uploadFile(filePath, fileUrl);
                }
                return batchId;
            } else {
                throw new RuntimeException("获取文件Url(s)失败，响应状态码:" + response.getStatusCodeValue() +
                        "   接口状态码:" + response.getBody().getCode() + "  msg:" + response.getBody().getMsg());
            }
        } catch (Exception e) {
            throw new RuntimeException("调用 MinerU API 出错：" + e.getMessage(), e);
        }
    }

//    private void uploadFile(String filePath, String url) {
//        try {
//            // 上传文件时，不需要 Authorization 头
//            HttpHeaders headers = new HttpHeaders();
//            // 不需要设置 Authorization！
//            // 重要！必须加这个 Content-Type，否则签名不对
//            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//
//            byte[] fileContent = Files.readAllBytes(Paths.get(filePath));
//            HttpEntity<byte[]> entity = new HttpEntity<>(fileContent, headers);
//
//            ResponseEntity<String> uploadResponse = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class);
//            if (uploadResponse.getStatusCode().is2xxSuccessful()) {
//                System.out.println(filePath + " uploaded successfully.");
//            } else {
//                System.out.println("Failed to upload " + filePath + ", status: " + uploadResponse.getStatusCode());
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    private void uploadFile(String filePath, String uploadUrl) {
        try {
            URL url = new URL(uploadUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("PUT");
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);
            // 不要设置Content-Type
            conn.setRequestProperty("Content-Length", String.valueOf(Files.size(Paths.get(filePath))));

            try (OutputStream os = conn.getOutputStream();
                 InputStream is = Files.newInputStream(Paths.get(filePath))) {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = is.read(buffer)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
            }

            int responseCode = conn.getResponseCode();
            if (responseCode / 100 == 2) {  // 2xx 成功
                System.out.println(filePath + " uploaded successfully.");
            } else {
                System.out.println("Failed to upload " + filePath + ", responseCode: " + responseCode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    // 轮询查询状态（GET方式）带最大重试次数
    public List<String> fetchExtractResultWithPolling(String batchId) throws InterruptedException {
        // 拼接URL
        String url = String.format(EXTRACT_RESULT_URL, batchId);

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(AUTHORIZATION_TOKEN);

        HttpEntity<Void> requestEntity = new HttpEntity<>(headers);

        int retryCount = 0;
        boolean allDone = false;
        List<String> zipUrls = new ArrayList<>();
        Set<String> processedFileNames = new HashSet<>();

        while (!allDone && retryCount < MAX_RETRIES * NUM_OF_FILES) {
            ResponseEntity<MinerUExtractResultResponse> response = restTemplate.exchange(
                    url, HttpMethod.GET, requestEntity, MinerUExtractResultResponse.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                if (response.getBody().getCode() == 0 && response.getBody().getMsg().equals("ok")) {
                    List<MinerUExtractResultResponse.extract_result_single> extractResults = response.getBody().getData().getExtractResult();

                    allDone = true; // 默认认为都完成，发现有pending再改
                    for (MinerUExtractResultResponse.extract_result_single extractResult : extractResults) {
                        String fileName = extractResult.getFileName();
                        String state = extractResult.getState();
                        if ("done".equals(state) && !processedFileNames.contains(fileName)) {
                            String zipUrl = extractResult.getFullZipUrl();
                            if (zipUrl != null) {
                                zipUrls.add(zipUrl);
                                processedFileNames.add(fileName);
                            }
                        } else if (!"done".equals(state) && !"failed".equals(state)) {
                            allDone = false;
                        } else if ("failed".equalsIgnoreCase(state)) {
                            throw new RuntimeException("MinerU获取full_zip_url失败，错误信息:" + fileName + "   " + extractResult.getErrMsg());
                        }
                    }
                } else {
                    throw new RuntimeException("Failed to fetch extract results, reason: " + response.getBody().getMsg());
                }
            } else {
                throw new RuntimeException("API request failed with status: " + response.getStatusCode());
            }

            if (!allDone) {
                retryCount++;
                Thread.sleep(RETRY_DELAY_MS);
            }
        }
        if (!allDone) {
            String message = retryCount >= MAX_RETRIES * NUM_OF_FILES
                    ? "任务超时：超过最大重试次数，仍有未完成文件，batchId: " + batchId
                    : "部分文件未完成处理，batchId: " + batchId;
            throw new RuntimeException(message);
        }

        return zipUrls;
    }
}